﻿using System;
using Basmus.ReadWrite;

namespace Basmus.Values.Attributive.ReadWrite
{
    public class NullableObjectElementsReaderWriterBuilder : IObjectElementsReaderWriterBuilder
    {
        private readonly IBindingBuilder _bindingBuilder;

        public NullableObjectElementsReaderWriterBuilder(IBindingBuilder bindingBuilder)
        {
            _bindingBuilder = bindingBuilder;
        }

        public IElementsReaderWriter<object> Build(ValuesContext valuesContext)
        {
            var elementType = _bindingBuilder.Build(valuesContext).ElementType;
            var underlyingType = Nullable.GetUnderlyingType(elementType);
            if (underlyingType != null)
            {
                object valueReaderWriterBuilder = null;
                if (underlyingType == typeof (Int32))
                {
                    valueReaderWriterBuilder = new Int32ReaderWriterBuilder();
                }
                else if (underlyingType == typeof (Boolean))
                {
                    valueReaderWriterBuilder = new BooleanReaderWriterBuilder();
                }
                else if (underlyingType == typeof (Guid))
                {
                    valueReaderWriterBuilder = new GuidReaderWriterBuilder();
                }
                else if (underlyingType.IsEnum)
                {
                    valueReaderWriterBuilder = typeof(EnumReaderWriterBuilder<>)
                        .MakeGenericType(underlyingType)
                        .GetConstructor(new Type[0])
                        .Invoke(null);
                }
                if (valueReaderWriterBuilder != null)
                {
                    var nullableReaderWriterBuilder = typeof (NullableReaderWriterBuilder<>)
                        .MakeGenericType(underlyingType)
                        .GetConstructor(new[] {typeof (IReaderWriterBuilder<>).MakeGenericType(underlyingType)})
                        .Invoke(new[] {valueReaderWriterBuilder});
                    var nullableReaderWriter = typeof (NullableReaderWriterBuilder<>)
                        .MakeGenericType(underlyingType)
                        .GetMethod("Build")
                        .Invoke(nullableReaderWriterBuilder, new object[] {valuesContext});
                    var objectElementsReaderWriter = ReflectionHelper
                        .GetObjectElementsReaderWriter(elementType, nullableReaderWriter);
                    return (IElementsReaderWriter<object>) objectElementsReaderWriter;
                }
            }
            return null;
        }
    }
}